﻿using Microsoft.Xna.Framework;
using OTAPI;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Terraria;
using Terraria.Audio;
using Terraria.DataStructures;
using Terraria.ID;
using Terraria.Localization;
using TerrariaApi.Server;
using TShockAPI;
using static TShockAPI.GetDataHandlers;

namespace TShock_AI
{
    [ApiVersion(2, 1)]
    public class TShock_AI : TerrariaPlugin
    {
        public override string Author => "星夜神花";
        public override string Description => "敌怪AI增强";
        public override string Name => "TShock_AI";
        public override Version Version => new Version(0, 0, 0, 3);
        public Config config;
        public TShock_AI(Main game) : base(game)
        {
        }
        public override void Initialize()
        {
            config = Config.LoadConfig();
            TShockAPI.Hooks.GeneralHooks.ReloadEvent += OnReloadEvent;
            Hooks.Npc.Spawn += OTAPI_NPC_Spawn;
            Hooks.Npc.PreAI += OTAPI_NPC_PreAI;
            Hooks.Npc.PostAI += OTAPI_NPC_PostAI;
            Hooks.Projectile.PreAI += OTAPI_Projectile_PreAI;
            Hooks.Projectile.PostAI += OTAPI_Projectile_PostAI;
            Hooks.Projectile.PostKilled += OTAPI_Projectile_PostKilled;
            Hooks.Npc.Killed += OTAPI_NPC_Killed;
            Hooks.Npc.Strike += OTAPI_NPC_Strike;

            LanguageManager.Instance.SetLanguage("zh-Hans");
            ItemDrop.Register((object sender, ItemDropEventArgs e) =>
            {
                if (e.Type != 0 && e.Type != 1176 && e.Player.Dead == false)
                {
                    TShock.Log.Write($"[{e.Player.Name}]丢弃{e.Stacks}个{Lang.GetItemNameValue(e.Type)}", System.Diagnostics.TraceLevel.Info);
                }
            });

            PlayerSlot.Register((object sender, PlayerSlotEventArgs e) =>
            {
                if (e.Slot == 58 && e.Stack != 0)
                {
                    TShock.Log.Write($"[{e.Player.Name}]拿了{e.Stack}个{Lang.GetItemNameValue(e.Type)}", System.Diagnostics.TraceLevel.Info);
                }
            });

            NewProjectile.Register((object sender, NewProjectileEventArgs e) =>
            {
                switch (e.Type)
                {
                    case 28:
                    case 29: 
                    case 470: 
                    case 637:
                    case 516:
                    case 519:
                    case 714:
                    case 773:
                    case 903:
                    case 904:
                    case 905:
                    case 906:
                    case 910:
                    case 911:
                        TShock.Log.Write($"[{e.Player.Name}]生成{Lang.GetProjectileName(e.Type)}在{e.Position}", System.Diagnostics.TraceLevel.Info);
                        break;
                }
            });

            //ChestItemChange.Register((object sender, ChestItemEventArgs e) =>
            //{
            //    if(e.Type != 0)
            //    {
            //        Console.WriteLine($"{e.Player.Name}放了{e.Stacks}个{Lang.GetItemName(e.Type)}");
            //    }
            //});

            ServerApi.Hooks.NetGetData.Register(this, (GetDataEventArgs e) =>
            {
                if (e.MsgID == PacketTypes.SpawnBossorInvasion)
                {
                    using (var data = new MemoryStream(e.Msg.readBuffer, e.Index, e.Length - 1))
                    {
                        BinaryReader reader = new BinaryReader(data);
                        int id = reader.ReadUInt16();
                        int type = reader.ReadUInt16();
                        TSPlayer player = TShock.Players[id];
                        if (player != null)
                        {
                            if (type > 0)
                            {
                                TSPlayer.All.SendMessage($"[{player.Name}]召唤了{Lang.GetNPCName(type)}",Color.Yellow);
                            }
                            else
                            {
                                TSPlayer.All.SendMessage($"[{player.Name}]召唤了一个奇怪的东西qwq",Color.White);
                            }
                        }
                    }
                }
            });

            PlayerDamage.Register(TSHOCKAPI_PlayerDamage);

            new Timer((object state) =>
            {
                for (int i = 0; i < TShock.Players.Length; i++)
                {
                    TSPlayer player = TShock.Players[i];
                    if (player != null && player.Dead == false && player.IsLoggedIn == false)
                    {
                        player.KillPlayer();
                        player.SendErrorMessage("请注册后登录游戏！");
                    }
                }
            }, "", 25 * 1000, 25 * 1000);
        }


        private void OTAPI_Projectile_PostKilled(Projectile projectile)
        {
            Projectile_AI ai = Projectile_AI.Projectile_Data[projectile.whoAmI];
            if (ai?.projectile == projectile)
            {
                try
                {
                    ai.OnPostKilled();
                }
                catch (Exception e)
                {
                    TShock.Log.Write(e.ToString(), System.Diagnostics.TraceLevel.Error);
                }
            }
            Projectile_AI.Projectile_Data[projectile.whoAmI] = null;
        }

        private void OTAPI_Projectile_PostAI(Projectile projectile)
        {
            try
            {
                Projectile_AI ai = Projectile_AI.Projectile_Data[projectile.whoAmI];
                if (ai?.projectile == projectile)
                {
                    ai.OnPostAI();
                }
            }
            catch (Exception e)
            {
                TShock.Log.Write(e.ToString(), System.Diagnostics.TraceLevel.Error);
            }
        }

        private HookResult OTAPI_Projectile_PreAI(Projectile projectile)
        {
            Projectile_AI ai = Projectile_AI.Projectile_Data[projectile.whoAmI];
            if (ai?.projectile != projectile)
            {
                return HookResult.Continue;
            }
            return ai.OnPreAI();
        }

        //private void ServerApi_NetGetData(GetDataEventArgs args)
        //{
        //    if (args.MsgID == PacketTypes.PlayerUpdate)
        //    {
        //        using (MemoryStream stream = new MemoryStream(args.Msg.readBuffer, args.Index, args.Length))
        //        {
        //            TSPlayer player = TShock.Players[stream.ReadByte()];
        //            byte control = (byte)stream.ReadByte();
        //            byte pulley = (byte)stream.ReadByte();
        //            player.SetBuff(BuffID.Gravitation);
        //            if(player.TPlayer.gravDir == 1f)
        //            {
        //                player.TPlayer.gravDir = -1f;
        //                NetMessage.SendData(13, number: player.Index);
        //            }
        //        }
        //    }
        //}

        private HookResult OTAPI_NPC_Strike(NPC npc, ref double cancelResult, ref int damage, ref float knockBack, ref int hitDirection, ref bool crit, ref bool noEffect, ref bool fromNet, Entity entity)
        {
            NPC_AI ai = NPC_AI.NPC_Data[npc.whoAmI];
            try
            {
                if (ai?.npc == npc)
                {
                    ai.OnAttackedMe(damage);
                }
            }
            catch (Exception e)
            {
                TShock.Log.Write(e.ToString(), System.Diagnostics.TraceLevel.Error);
            }
            return HookResult.Continue;
        }

        private void OTAPI_NPC_Killed(NPC npc)
        {
            NPC_AI ai = NPC_AI.NPC_Data[npc.whoAmI];
            if (ai?.npc != npc)
            {
                return;
            }
            ai.OnKilled();
            NPC_AI.NPC_Data[npc.whoAmI] = null;
        }

        private void TSHOCKAPI_PlayerDamage(object sender, PlayerDamageEventArgs e)
        {
            if (e.PlayerDeathReason._sourceNPCIndex != -1)
            {
                NPC npc = Main.npc[e.PlayerDeathReason._sourceNPCIndex];
                if (npc == NPC_AI.NPC_Data[e.PlayerDeathReason._sourceNPCIndex]?.npc)
                {
                    NPC_AI.NPC_Data[e.PlayerDeathReason._sourceNPCIndex].OnAttackedPlayer(e.Player, e.Damage);
                }
            }
            else if (e.PlayerDeathReason._sourceProjectileIndex != -1)
            {
                Projectile projectile = Main.projectile[e.PlayerDeathReason._sourceProjectileIndex];
                if (projectile == Projectile_AI.Projectile_Data[e.PlayerDeathReason._sourceProjectileIndex]?.projectile)
                {
                    Projectile_AI.Projectile_Data[Main.projectile[e.PlayerDeathReason._sourceProjectileIndex].whoAmI]?.OnAttackedPlayer(e.Player, e.Damage);
                }
            }
        }

        private HookResult OTAPI_NPC_Spawn(ref int index)
        {
            NPC npc = Main.npc[index];
            switch (npc.netID)
            {
                case NPCID.KingSlime:
                    NPC_AI.NPC_Data[npc.whoAmI] = new KingSlimeAI(npc);
                    break;
                case NPCID.EyeofCthulhu:
                    NPC_AI.NPC_Data[npc.whoAmI] = new EyeofCthulhuAI(npc);
                    break;
                case NPCID.BrainofCthulhu:
                    NPC_AI.NPC_Data[npc.whoAmI] = new BrainofCthulhuAI(npc);
                    break;
                case NPCID.Creeper:
                    NPC_AI.NPC_Data[npc.whoAmI] = new CreeperAI(npc);
                    break;
                case NPCID.WallofFlesh:
                    NPC_AI.NPC_Data[npc.whoAmI] = new WallofFleshAI(npc);
                    break;
                case NPCID.WallofFleshEye:
                    NPC_AI.NPC_Data[npc.whoAmI] = new WallofFleshEyeAI(npc);
                    break;
                case NPCID.SkeletronHead:
                    NPC_AI.NPC_Data[npc.whoAmI] = new SkeletronHeadAI(npc);
                    break;
                case NPCID.SkeletronHand:
                    NPC_AI.NPC_Data[npc.whoAmI] = new SkeletronHandAI(npc);
                    break;
                case NPCID.EaterofWorldsHead:
                    npc.active = false;
                    TSPlayer.All.SendMessage("Eater of Worlds已禁用!", Color.Green);
                    return HookResult.Cancel;
                    NPC_AI.NPC_Data[npc.whoAmI] = new EaterofWorldsHeadAI(npc);
                    break;
                case NPCID.EaterofWorldsBody:
                    NPC_AI.NPC_Data[npc.whoAmI] = new EaterofWorldsBodyAI(npc);
                    break;
                case NPCID.Deerclops:
                    NPC_AI.NPC_Data[npc.whoAmI] = new DeerclopsAI(npc);
                    break;
                case NPCID.QueenBee:
                    NPC_AI.NPC_Data[npc.whoAmI] = new QueenBeeAI(npc);
                    break;
                //case NPCID.DukeFishron:
                //    NPC_AI.NPC_Data[npc.whoAmI] = new DukeFishronAI(npc);
                //    break;
                case NPCID.Antlion:
                    NPC_AI.NPC_Data[npc.whoAmI] = new AntlionAI(npc);
                break;
                default:
                    NPC_AI.NPC_Data[npc.whoAmI] = new NPC_AI(npc, new float[] { });
                    break;
            }
            return HookResult.Continue;
        }

        private void OTAPI_NPC_PostAI(NPC npc)
        {
            NPC_AI ai = NPC_AI.NPC_Data[npc.whoAmI];
            if (ai?.npc != npc)
            {
                return;
            }
            ai.OnPostAI();
        }

        private HookResult OTAPI_NPC_PreAI(NPC npc)
        {
            NPC_AI ai = NPC_AI.NPC_Data[npc.whoAmI];
            if (ai?.npc != npc)
            {
                return HookResult.Continue;
            }
            return ai.OnPreAI();
        }

        private void OnReloadEvent(TShockAPI.Hooks.ReloadEventArgs e)
        {
            config = Config.LoadConfig();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                TShockAPI.Hooks.GeneralHooks.ReloadEvent -= OnReloadEvent;
                Hooks.Npc.Spawn -= OTAPI_NPC_Spawn;
                Hooks.Npc.PreAI -= OTAPI_NPC_PreAI;
                Hooks.Npc.PostAI -= OTAPI_NPC_PostAI;
            }
            base.Dispose(disposing);
        }
    }


}
